import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import ChainNode.ChainNode;
import ChainNode.ChainWithHeaderNode;


public class Traduccion {

	private BufferedWriter bWriter;
    private PrintWriter printWriter;
    
    private ArrayList<ChainWithHeaderNode> chainNodeArrayList;
    int counter=0;
    int intmain=0;
    int printf=0;
    int multiplePrintf=0;
    int multipleReader=0;
    int mainProgram=0;
    int cout=0;
    int vardeclaracion=0;
    int constDeclaracion=0;
    int forDeclaracion=0;
    int repeatDeclaracion=0;
    int whileDeclaracion=0;
    int numVariables=0;
    int readf=0;
    int funcionLlamado=0;
    
    
	public Traduccion(ArrayList<ChainWithHeaderNode> chainNodeArrayList1){
		
		try {
			bWriter= new BufferedWriter(new FileWriter( new File("codeC.cpp") ) );
			printWriter= new PrintWriter(bWriter);
            printWriter.write("");
            String bufferIn;
            cabecera();
            chainNodeArrayList=chainNodeArrayList1;
        	traduccionc();
        	printWriter.write("\n");
            
            bWriter.close();
            printWriter.close();
            
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
	}
	
	private void cabecera() {
		printWriter.write("#include<conio.h>\n");
		printWriter.write("#include<stdio.h>\n");
		printWriter.write("#include<iostream>\n");
		printWriter.write("#include<math.h>\n");
		printWriter.write("using namespace std;\n");
		
		
		
	}

	public void traduccionc(){
		
		
		for(ChainWithHeaderNode c: chainNodeArrayList){
			
			ChainNode chainNode = c.headerNode.next;
			
			for(int i=0; i<c.size;i++){
				if(chainNode.element!=null){
					Token token = (Token)chainNode.element;
					if(token.kind==0){
						intmain++;
						mainProgram=1;
					}
					else if(token.kind==13){
						
						if(vardeclaracion==1 || numVariables==0){
							printWriter.write("int main()");	
							numVariables=100;
						}
						printWriter.write("{");
						vardeclaracion=0;
						
					}
					else if(token.image.equals("end")){
						if(intmain==1 && forDeclaracion==0 && whileDeclaracion==0){
				            printWriter.write("getch();\n");
				            printWriter.write("return 0;\n");	
				            intmain=0;
						}
						if(forDeclaracion==1){
							forDeclaracion=2;
						}
						if(whileDeclaracion==1){
							whileDeclaracion=2;
						}
						printWriter.write("}");
					}
					else if(token.kind==62 && (forDeclaracion==2 || whileDeclaracion==2)){
						if(forDeclaracion==2)
						forDeclaracion=0;
						else if(whileDeclaracion==2)
							whileDeclaracion=0;
					}
					else if(token.kind>=54 && token.kind<=57){
							printWriteReadLn(token);
						
					}
					else if(token.kind==93){
						
						for(int j=0; j<token.image.length();j++){
							if(token.image.charAt(j) == 39){
								printWriter.write("\"");
							}
							else{
								printWriter.write(token.image.charAt(j));
							}
						}
					}
					// declaracion de variables
					else if(token.kind==50){
						varchainNode(chainNode,c.size,i);
						i=c.size;
						vardeclaracion=1;
						numVariables++;
					}
					// declaracion de constantes
					else if(token.kind==15){
						constChainNode(chainNode,c.size,i);
						i=c.size;
						vardeclaracion=1;
					}
					//for declaration
					else if(token.kind==22){
						forChainNode(chainNode,c.size,i);
						i=c.size;
						forDeclaracion=1;
					}
					//while declaration
					else if(token.kind==51){
						whileChainNode(chainNode,c.size,i,true);
						whileDeclaracion=1;
						i=c.size;
					}
					//repeat declaration
					else if(token.kind==42){
						repeatDeclaracion=1;
						printWriter.write("do");
						printWriter.write("{");
					}
					//until token
					else if(token.kind==48){
						printWriter.write("}");
						whileChainNode(chainNode, c.size, i,false);
						i=c.size;
					}
					else if(token.kind==72){
						printWriter.write("=");
					}
					else if(token.kind==76){
						printWriter.write("!=");
					}
					else if(mainProgram!=1){
						ChainNode next = chainNode.next;
						if(next.element!=null){
						  Token t = (Token)next.element;
						  endPro(token,t);
						}
						else{
							endPro(token,new Token());
						}
					}
				}
				chainNode= chainNode.next;
			}
			mainProgram=0;
			printf=0;
			readf=0;
			multiplePrintf=0;
			multipleReader=0;
			funcionLlamado=0;
			printWriter.write("\n");
			if(printf==1){
				printWriter.write("printf(\"\\n\");");
				printf=0;
				readf=0;
				printWriter.write("\n");
			}
		}
		
	}

	

	private void constChainNode(ChainNode chainNode, int size, int j) {

		String constantes ="";
		printWriter.write("const ");
		chainNode= chainNode.next;
		Token asign= new Token();
		boolean asignado=false;
		String tipo = "";
		String dato = "";
		j++;
		//printWriter.write(variable.image);
		for( int i=j; i<size;i++){
			Token token = (Token)chainNode.element;

			if(token.kind==103 && !asignado){
				constantes+=token.image;
			}
			else if(token.kind==103){
				dato+=token.image;
			}
			else if(token.kind==63 && !asignado){
				constantes+=token.image;
			}
			else if(token.kind==73){
				asign.image="=";
				asignado=true;
			}
			else if(token.kind==93){
				tipo="text";
				dato+=token.image;
			}
			else if(token.kind==94){
				tipo="char";
				dato+=token.image;
			}
			else if(token.kind==95){
				tipo="double";
				dato+=token.image;
			}
			else if(token.kind==83){
				tipo="int";
				dato+=token.image;
			}
			
			else {

				if(token.kind==62){
					printWriter.write(" " +tipo + " ");
					printWriter.write(constantes + " ");
					printWriter.write(asign.image + " ");
					printWriter.write(" " + dato + " ");
					printWriter.write(";");
					dato="";
					constantes="";
					tipo="";
				}
				
			}
			chainNode= chainNode.next;
			
		}
		
		
		
		
	}

	private void whileChainNode(ChainNode chainNode, int size, int j, boolean flag) {
		
		printWriter.write("while");
		printWriter.write("(");
		chainNode= chainNode.next;
		for( int i=j; i<size;i++){
			
			if(chainNode.element!=null){
				Token token = (Token)chainNode.element;
				if(token.kind==17){
					printWriter.write(")");
				}
				else if(token.kind==76){
					printWriter.write("!=");
				}
				else if(token.kind==73){
					printWriter.write("==");
				}
				else{
					boolean oper=getoper(token);
					if(!oper){
						printWriter.write(token.image);
					}
					
				}
			}
			chainNode= chainNode.next;
		}
		if(!flag){
			printWriter.write(")");
		}
	}

	private void forChainNode(ChainNode chainNode, int size, int j) {
		
		chainNode= chainNode.next;
		Token varAux= (Token)chainNode.element;
		int au=0;
		printWriter.write("for");
		printWriter.write("(");
		for( int i=j; i<size;i++){
			if(chainNode.element!=null){
				Token token = (Token)chainNode.element;
				if(token.kind==72){
					printWriter.write("=");
					
				}
				else if(token.kind==45){
					printWriter.write("<=");
					au=1;
				}
				else {
					
					if(token.kind==17){
						printWriter.write(")");
					}
					else{
						if(i!=j){
							printWriter.write(token.image);
							printWriter.write(";");
							printWriter.write(varAux.image);
						}
						
						else{
							boolean oper=getoper(token);
							if(!oper){
								printWriter.write(token.image);
							}
						}
						if(au==1){
							printWriter.write("++");
							au=0;
						}
					}
				}
			}
			chainNode= chainNode.next;
		}
		
	}

	private void varchainNode(ChainNode chainNode, int size, int j) {
		
		String variables ="";
		
		for( int i=j; i<size;i++){
			Token token = (Token)chainNode.element;
			if(token.kind>=88 && token.kind<=92){
				if(token.kind==88){
					printWriter.write(" string ");
				}
				else if(token.kind==89){
					printWriter.write(" int ");
				}
				else if(token.kind==90){
					printWriter.write(" bool ");
				}
				else if(token.kind==91){
					printWriter.write(" double ");
				}
				else if(token.kind==92){
					printWriter.write(" char ");
				}
				printWriter.write(variables);
			}
			else if(token.kind==103){
				variables+=token.image;
			}
			else if(token.kind==63){
				variables+=token.image;
			}
			else {
				if(token.kind!=64 && token.kind!=50){
					printWriter.write(token.image);
					if(token.kind==62){
						variables="";
					}
				}
			}
			chainNode= chainNode.next;
		}
	
	}

	private void printWriteReadLn(Token token) {
		if(token.kind==54 || token.kind==55){
			printWriter.write("cout");
			if(token.kind==55){
				printf=1;
			}
			multiplePrintf=1;
		}
		else if(token.kind==56 || token.kind==57){
			printWriter.write("cin");
			if(token.kind==57){
				readf=1;
				
			}
			multipleReader=1;
		}
	}
	
	private void endPro(Token token, Token t){
		
		if((token.kind>=98 && token.kind<=103) && t.kind==58 ){
			funcionLlamado=1;
			printWriter.write(token.image);
		}
		else if(funcionLlamado==1 && t.kind==59){
			funcionLlamado=0;
			
				printWriter.write(token.image);
				printWriter.write(")");
			
		}
		else if(multiplePrintf==1 && funcionLlamado==0){
		  if(token.kind==58 || token.kind==63){
			  printWriter.write("<<");
		  }
		  else if(token.kind==59){}
		  else{
			  printWriter.write(token.image);
		  }
		}
		else if(multipleReader==1){
			  if(token.kind==58 || token.kind==63){
				  printWriter.write(">>");
			  }
			  else if(token.kind==59){}
			  else{
				  printWriter.write(token.image);
			  }
			}
		else{
			
			boolean specialsymbol = getoper(token);
			if(!specialsymbol){
				
				printWriter.write(token.image);
			}
		}
		
	}

	private boolean getoper(Token token) {
        int t = token.kind;
		if(t==12 || t==31 || t==36 || t==34){
			if(t==12){
				printWriter.write("&&");
			}
			else if(t==31){
				printWriter.write("%");
			}
			else if(t==36){
				printWriter.write("||");
			}
			else{
				printWriter.write("!");
			}
			return true;
		}
		return false;
	}
	
}
